/***
 * Copyright (c) 2021-2031 murenchao
 * fig is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *       http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */
package cool.taomu.software.fig.crypto

import java.security.NoSuchAlgorithmException
import java.security.SecureRandom
import java.util.UUID
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
import org.slf4j.Logger
import org.slf4j.LoggerFactory

class AES implements ICrypto {
    final Logger LOG = LoggerFactory.getLogger(AES);

    /** The default iv. */
    byte[] defaultIv = #[
        0x32 as byte,
        0x46 as byte,
        0xfe as byte,
        0xab as byte,
        0xfc as byte,
        0x2d as byte,
        0x15 as byte,
        0xfa as byte,
        0x32 as byte,
        0x46 as byte,
        0xfe as byte,
        0xab as byte,
        0xfc as byte,
        0x2d as byte,
        0x15 as byte,
        0xfa as byte
    ];

    /** The Constant key. */
    String key = "70rEwsfQZBUW+LB2l16RfMgcARMHqDsV";

    ICrypto c;

    byte[] src;

    new(byte[] src) {
        this.src = src;
    }

    new(String key, ICrypto c) {
        this.key = key;
        this.c = c;
    }

    new(String key, byte[] iv, ICrypto c) {
        this.key = key;
        this.c = c;
        this.defaultIv = iv;
    }

    new(ICrypto c) {
        this.c = c;
    }

    /**
     * 加密.
     */
    def byte[] encryptBytes(byte[] src) throws Exception {
        var SecretKey secretKey = new SecretKeySpec(this.key.getBytes(), "AES");
        var Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        var IvParameterSpec IVSpec = new IvParameterSpec(defaultIv);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, IVSpec);
        return cipher.doFinal(src);
    }

    /**
     * 解密.
     */
    def byte[] decryptBytes(byte[] srcBytes) throws Exception {
        var SecretKey secretKey = new SecretKeySpec(this.key.getBytes(), "AES");
        var IvParameterSpec IVSpec = new IvParameterSpec(defaultIv);
        var Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKey, IVSpec);
        return cipher.doFinal(srcBytes);
    }

    /**
     * Gen key.
     */
    private def static String createAESKey() throws NoSuchAlgorithmException {
        var byte[] keyBytes = UUID.randomUUID().toString().getBytes();
        var KeyGenerator desEde = KeyGenerator.getInstance("AES");
        desEde.init(new SecureRandom(keyBytes));
        var SecretKey key = desEde.generateKey();
        var ICrypto base64 = new Base64(key.getEncoded());
        return new String(base64.encode());
    }

    override byte[] encode() {
        if (c !== null) {
            try {
                return this.encryptBytes(c.encode());
            } catch (Exception e) {
                LOG.info("encode : ", e);
            }
        }
        try {
            return this.encryptBytes(src);
        } catch (Exception e) {
            LOG.info("encode : ", e);
        }
        return null;
    }

    override byte[] decode() {
        try {
            if (c !== null) {
                var byte[] des3Src = this.decryptBytes(c.getData());
                c.setData(des3Src);
                return c.decode();
            } else {
                return this.decryptBytes(this.src);
            }
        } catch (Exception e) {
            LOG.info("decode : ", e);
        }
        return null;
    }

    override byte[] getData() {
        return this.src;
    }

    override setData(byte[] src) {
        this.src = src;
        return this;
    }
}
